#include "Col.ph"
#ifdef __GNUG__
#pragma implementation
#endif

#include "SeqColl.h"
#include "Class.h"

#include "Error.h"

char *cNotLegalIndex   = "index error (= %d) < 0 or > Size() (= %d) - 1";
char *cNotLegalIndex0  = "index error (= %d) < 0 or > Size() (= %d)";

//---- SeqCollection ----------------------------------------------------------

NewAbstractMetaImpl0(SeqCollection,Collection);

SeqCollection::SeqCollection()
{
}

Object *SeqCollection::Add(Object *op)
{
	if ( IsArgNull("Add", op) )
		return op;
		
	return primAddAt(op, Size());
}

Object *SeqCollection::AddFirst(Object *op)
{
	if ( IsArgNull("AddFirst", op) )
		return op;

	return primAddAt(op, 0);
}

Object *SeqCollection::AddLast(Object *op)
{
	if ( IsArgNull("AddLast", op) )
		return op;

	return primAddAt(op, Size());
}

Object *SeqCollection::AddAt(Object *op, int idx)
{
	if ( IsArgNull("AddAt", op) )
		return op;
	if ( NotLegalIndex0("AddAt", idx) )
		return op;

	return primAddAt(op, idx);
}

Object *SeqCollection::AddBefore(Object *op, Object *after)
{
	if ( IsArgNull("AddBefore - op", op) ||
		IsArgNull("AddBefore - after", after) )
		return op;
		
	return AddRelative(op, eEqValue, 0, after);
}

Object *SeqCollection::AddBeforePtr(Object *op, Object *after)
{
	if ( IsArgNull("AddBeforePtr - op", op) ||
		IsArgNull("AddBeforePtr - after", after) )
		return op;
		
	return AddRelative(op, eEqPointer, 0, after);
}

Object *SeqCollection::AddAfter(Object *op, Object *before)
{
	if ( IsArgNull("AddAfter - op", op) ||
		IsArgNull("AddAfter - before", before) )
		return op;
		
	return AddRelative(op, eEqValue, 1, before);
}

Object *SeqCollection::AddAfterPtr(Object *op, Object *before)
{
	if ( IsArgNull("AddAfterPtr - op", op) ||
		IsArgNull("AddAfterPtr - before", before) )
		return op;
		
	return AddRelative(op, eEqPointer, 1, before);
}

Object *SeqCollection::Remove(Object *op)
{
	if ( IsArgNull("Remove", op) )
		return 0;
		
	return RemoveRelative(op, eEqValue, 0);
}

Object *SeqCollection::RemovePtr(Object *op)
{
	if ( IsArgNull("RemovePtr", op) )
		return 0;
		
	return RemoveRelative(op, eEqPointer, 0);
}

Object *SeqCollection::PutAt(Object *op, int idx)
{
	if ( IsArgNull("PutAt", op) )
		return op;
	if ( NotLegalIndex("PutAt", idx) )
		return op;

	return primPutAt(op, idx);
}

Object *SeqCollection::RemoveFirst()
{
	if ( Size() > 0 )
		return primRemoveAt(0);

	return 0;
}

Object *SeqCollection::RemoveLast()
{
	if ( Size() > 0 )
		return primRemoveAt(Size() - 1);

	return 0;
}

Object *SeqCollection::RemoveAt(int idx)
{
	if ( NotLegalIndex("RemoveAt", idx) )
		return 0;

	return primRemoveAt(idx);
}

Object *SeqCollection::RemoveBefore(Object *after)
{
	if ( IsArgNull("RemoveBefore", after) )
		return after;
		
	return RemoveRelative(after, eEqValue, -1);
}

Object *SeqCollection::RemoveBeforePtr(Object *after)
{
	if ( IsArgNull("RemoveBeforePtr", after) )
		return 0;
		
	return RemoveRelative(after, eEqPointer, -1);
}

Object *SeqCollection::RemoveAfter(Object *before)
{
	if ( IsArgNull("RemoveAfter", before) )
		return 0;

	return RemoveRelative(before, eEqValue, +1);
}

Object *SeqCollection::RemoveAfterPtr(Object *before)
{
	if ( IsArgNull("RemoveAfterPtr", before) )
		return 0;

	return RemoveRelative(before, eEqPointer, +1);
}

//---- accessing ----
		
Object *SeqCollection::Find(Object *op)
{
	if ( IsArgNull("Find", op) )
		return 0;
	return primIndexOf(op, 0, 0);
}

Object *SeqCollection::FindPtr(Object *op)
{
	if ( IsArgNull("FindPtr", op) )
		return 0;
	return primIndexOfPtr(op, 0, 0);
}

Object *SeqCollection::At(int idx)
{
	if ( NotLegalIndex("At", idx) )
		return 0;
	return primAt(idx);
}

Object *SeqCollection::Before(Object *op)
{
	if ( ! op )
		return 0;
	return primIndexOf(op, -1, 0);
}

Object *SeqCollection::BeforePtr(Object *op)
{
	if ( ! op )
		return 0;
	return primIndexOfPtr(op, -1, 0);
}

Object *SeqCollection::After(Object *op)
{
	if ( ! op )
		return 0;
	return primIndexOf(op, +1, 0);
}

Object *SeqCollection::AfterPtr(Object *op)
{
	if ( ! op )
		return 0;
	return primIndexOfPtr(op, +1, 0);
}

Object *SeqCollection::First()
{
	if ( Size() > 0 )
		return primAt(0);
	return 0;
}

Object *SeqCollection::Last()
{
	if ( Size() > 0 )
		return primAt(Size() - 1);
	return 0;
}

int SeqCollection::IndexOf(Object *op)
{
	int idx= 0;

	if ( ! op )
		return -1;
	primIndexOf(op, 0, &idx);
	return idx;
}

int SeqCollection::IndexOfPtr(Object *op)
{
	int idx= 0;

	if ( ! op )
		return -1;
	primIndexOfPtr(op, 0, &idx);
	return idx;
}

Object *SeqCollection::AnyElement()
{
	return First();
}

void SeqCollection::RemoveDeleted()
{
	Error("RemoveDeleted", "should not be called");
}

Object *SeqCollection::AddRelative(Object *op, EqualType eq, int offset,
								Object *to)
{
	int idx= 0, edx;

	if ( eq )
		primIndexOf(to, 0, &idx);
	else
		primIndexOfPtr(to, 0, &idx);
	if ( idx >= 0 ) {
		edx= idx + offset;
		if ( edx >= 0 && edx <= Size() )
			return primAddAt(op, edx);
	}
	return op;
}

Object *SeqCollection::RemoveRelative(Object *to, EqualType eq, int offset)
{
	int idx= 0, edx;

	if ( eq )
		primIndexOf(to, 0, &idx);
	else
		primIndexOfPtr(to, 0, &idx);
	if ( idx >= 0 ) {
		edx= idx + offset;
		if ( edx >= 0 && edx < Size() )
			return primRemoveAt(edx);
	}
	return 0;
}


Object *SeqCollection::primAddAt(Object *op, int)
{
	AbstractMethod("primAddAt");
	return op;
}

Object *SeqCollection::primRemoveAt(int)
{
	AbstractMethod("primRemoveAt");
	return 0;
}

Object *SeqCollection::primPutAt(Object *op, int)
{
	AbstractMethod("primPutAt");
	return op;
}

Object *SeqCollection::primIndexOf(Object *, int, int *idx)
{
	AbstractMethod("primIndexOf");
	if ( idx )
		*idx= -1;
	return 0;
}

Object *SeqCollection::primIndexOfPtr(Object *, int, int *idx)
{
	AbstractMethod("primIndexOfPtr");
	if ( idx )
		*idx= -1;
	return 0;
}

Object *SeqCollection::primAt(int idx)
{
	register int i;
	register Object *op;

	Iter next(this);
	for ( i= 0; op= next(); i++ )
		if ( i == idx )
			break;
	return op;
}

